I reviewed docker.io-app 29.1.3-0ubuntu5 as checked into stonking. This is
a shallow, tool-assisted MIR security review rather than an in-depth audit.
Findings below were derived from the auto-generated audit artifacts in this
directory (packaging.txt, binaries.txt, *.txt tool outputs) and this request.

docker.io-app is the Ubuntu-only repackaging of the Moby Docker engine
(engine/, the `dockerd` daemon), the Docker CLI (cli/), tini
(`docker-init`, the PID-1 subreaper used as the container init) and the
`docker-trust` CLI plugin (cli-plugins). It is built as a mostly-static Go
binary with a small amount of C (tini, libnetwork's `docker-proxy`,
`contrib/syscall-test`). It provides an OCI-compliant container runtime,
exposing a Unix socket API (/var/run/docker.sock) and an optional TCP/REST
API. The daemon runs as root by design (it manages namespaces, cgroups,
seccomp, AppArmor and storage drivers). Only `bin:docker.io` is being
promoted to main; `docker-doc` stays in universe.

- CVE History
  - Per the MIR template, docker.io-app has had 19 security issues; counting
    the predecessor src:docker.io the full history is 65 issues
    (https://ubuntu.com/security/cves?package=docker.io-app and
    https://ubuntu.com/security/cves?package=docker.io). Historical fixes
    were delivered via new-upstream-version uploads (e.g. 26.1.3-0ubuntu2,
    24.0.7-0ubuntu3) as documented in the Docker SRU exception
    
(https://documentation.ubuntu.com/project/SRU/reference/exception-Docker-Updates/).
    Upstream (moby/moby) is responsive and the package has effectively been
    treated as supported-in-main for some time already.

- Build-Depends
  - From the build log "Merged Build-Depends":
    bash-completion, ca-certificates, cmake, debconf (>= 0.5),
    debhelper-compat (= 12), dh-apparmor, dh-exec, dh-golang, git,
    golang-1.24-go, libapparmor-dev, libbtrfs-dev | btrfs-progs (<< 4.16.1~),
    libdevmapper-dev (>= 2:1.02.68~), libltdl-dev, libnftables-dev,
    libseccomp-dev, libsystemd-dev (>= 209~), pkg-config, po-debconf, procps,
    tzdata, build-essential, fakeroot.
  - Sensitive libraries linked: libapparmor (AppArmor integration),
    libseccomp (seccomp profiles), libsystemd (journald logger),
    libnftables (nftables firewall driver), libdevmapper / libbtrfs (storage
    drivers), libltdl (dynamic plugin loading).
  - golang-1.24 (1.24.13-2) is used for the (mostly static) Go build;
    Built-Using records glibc and golang-1.24.
  - Runtime Recommends of note: pigz (parallel gzip for image-layer
    decompression - has its own MIR, LP #2150649), ubuntu-fan
    (Canonical-specific fan networking - kernel team will re-promote it to
    main once this MIR completes).

- pre/post inst/rm scripts
  - `preinst`: aborts configuration if the legacy aufs storage driver
    directory `/var/lib/docker/aufs` exists, asking the user to remove it.
  - `postinst`: creates the `docker` system group (used to set the group on
    `docker.sock`); handles ZFS dataset creation/migration for `/var/lib/docker`
    (gated on `zfs` being available and the `zfs` module being loaded,
    guarded against missing commands and only migrating for old versions);
    asks a debconf high-priority question (`docker.io/restart`) before
    restarting the daemon on upgrades (with explicit handling to avoid
    double-prompting); reloads the AppArmor profile; enables `docker.service`
    and `docker.socket` via `dh_installsystemd`; starts the daemon on first
    install via `dh_installinit --no-start` shim.
  - `prerm`: stops `docker.service`/`docker.socket`; on `remove`, copies
    `nuke-graph-directory.sh` into `/var/lib/docker/` so it survives package
    removal and can purge the graph directory later.
  - `postrm`: on `purge`, runs `nuke-graph-directory.sh` against
    `/var/lib/docker`; purges systemd units, debconf db and AppArmor bits.
  - The scripts are consistent: `prerm`/`postrm` clean up what
    `preinst`/`postinst` set up. One lintian informational note,
    `postinst-uses-db-input` (postinst:100), is intentional and documented
    in-line (the maintainer explains why a `.config` script would cause
    double prompting).

- init scripts
  - None (SysV initscripts section empty). The daemon is managed exclusively
    via systemd.

- systemd units
  - `docker.service` and `docker.socket` are shipped under
    `/usr/lib/systemd/system/`. `docker.socket` creates
    `/var/run/docker.sock` (group `docker`, mode 0660) and activates
    `docker.service`. The daemon runs as root by design (namespaces, cgroups,
    seccomp, storage drivers). No `DBus` activation, no socket activation of
    external interfaces.

- dbus services
  - None.

- setuid binaries
  - None. `packaging.txt` setuid/setgid/fs-capabilities sections are empty.
    (Consistent with the MIR template's "no suid/sgid binaries".)

- binaries in PATH
  - `/usr/bin/docker` (CLI, ~31 MB), `/usr/bin/dockerd` (daemon, ~84 MB),
    `/usr/bin/docker-init` (tini, ~806 KB, statically linked by design),
    `/usr/bin/docker-proxy` (libnetwork userland proxy, ~2.3 MB). Plus the
    `docker-trust` CLI plugin under `/usr/libexec/docker/cli-plugins/`.

- sudo fragments
  - None shipped. (`grep` only finds `sudo` mentioned in documentation
    strings instructing users how to add themselves to the `docker` group.)

- polkit files
  - None.

- udev rules
  - None.

- unit tests / autopkgtests
  - Build-time: a superficial Go test suite runs and will fail the build on
    error. A full integration suite is not run at build time as it requires
    non-trivial network setup and isolation-machine capabilities.
  - Autopkgtest: present and passing locally on amd64, but flaky across
    supported architectures due to Docker Hub pull rate-limit constraints
    (a Launchpad/infrastructure limitation). The Server team relies on local
    autopkgtest runs when flakiness spikes and intends to move away from
    depending on Docker Hub in the long run.

- cron jobs
  - None.

- Build logs
  - No compiler errors. Compiler/lintian warnings are limited to:
      * `dh_golang` LTO-stripping warnings for cgo (expected; cgo does not
        support LTO and the flags are stripped automatically).
      * `dh_installdocs` cannot auto-detect the main package for `docker-doc`
        (cosmetic).
      * `rehash: warning: skipping ca-certificates.crt` (tooling).
      * `groff-message` warnings/errors when rendering the docker manpages
        (tbl preprocessor / `troff` segfault) - a manpage-rendering tooling
        issue, not a build defect; lintian also reports `E: Lintian run
        failed (runtime error)` as a consequence.
      * `dpkg-gencontrol: ... ${misc:Static-Built-Using} unused` (cosmetic).
  - No incautious use of malloc/sprintf or other compiler red flags.

- Processes spawned
  - The daemon and CLI extensively shell out to system utilities
    (iptables/nft, fuse-overlayfs, ip, user/group lookups, containerd,
    container runtimes, etc.). Semgrep flags ~20 `dangerous-exec-command`
    sites and gosec flags 3 G204 (CWE-78) sites in `cli/`:
    `cli/cli/connhelper/commandconn/commandconn.go:49`,
    `cli/cli/command/image/build/internal/git/gitutils.go:206`,
    `cli/e2e/testutils/plugins.go:88`. All inspected call sites pass
    argument lists (not shell strings) derived from configuration or
    trusted inputs; none were found to splice untrusted user data into a
    shell. tini uses `execvp(argv[0], argv)` (expected). The C
    `contrib/syscall-test/*` helpers use `execvp` (test-only, not shipped
    in the binary package).

- Memory management
  - Go is garbage-collected; the small amount of C is in tini and
    `contrib/syscall-test`. tini uses a single `calloc` for child args
    (`tini/src/tini.c:374`) with a checked return code; no manual malloc/free
    patterns to audit. cppcheck reports only uninitialised-variable errors
    in vendored Darwin cgo code (`process_collector_mem_cgo_darwin.c`),
    which is not built on Linux.

- File IO
  - Paths are derived from configuration (`/var/lib/docker`, context dirs,
    TLS material, manifest stores, etc.). gosec G304 (CWE-22, 20 occurrences
    in `cli/`) flags `os.Open`/`os.ReadFile` with variables; these are the
    expected behaviour for a tool whose purpose is to read user-supplied
    files (Dockerfiles, contexts, TLS certs, manifests). Directory
    permissions are flagged by gosec G301 (4 sites) and file-write perms by
    G306 (3 sites) - all in `cli/cli/{manifest,context}` stores and
    `cli/cli/command/image/build.go`; these write to the user's docker config
    directory. Not a cross-user privilege issue.

- Logging
  - tini uses `PRINT_FATAL`/`PRINT_DEBUG` macros that format `strerror(errno)`
    into fixed buffers via `snprintf`-style calls; no tainted format strings.
    The engine uses structured logging (logrus) and a journald driver
    (libsystemd). Semgrep flags some `fprintf` to `http.ResponseWriter` in
    networkdb/diagnostic test helpers (`no-fprintf-to-responsewriter`) -
    these are internal diagnostic HTTP endpoints, not user-facing web
    content.

- Environment variable usage
  - tini reads `TINI_SUBREAPER`, `TINI_KILL_PROCESS_GROUP`, `TINI_VERBOSITY`
    (string comparisons, no execution). The engine reads numerous `DOCKER_*`
    configuration variables; the Python `ssd.py` helper iterates over
    `$PATH`. No environment variable was found to be passed unsanitised to a
    shell or used as a privileged function argument.

- Use of privileged functions
  - The daemon intentionally runs as root and uses the full set of privileged
    primitives (namespace/cgroup/seccomp/AppArmor setup, mount, network
    configuration). This is by design for a container runtime. tini uses
    `setpgid`/`tcsetpgrp`/`sigprocmask` and registers as a child subreaper.
    `contrib/syscall-test/*` calls `setuid`/`setgid`/`socket` (test-only,
    not shipped). No setuid/sgid binaries or file capabilities are installed
    on the package.

- Use of cryptography / random number sources etc
  - Vendored crypto: `golang.org/x/crypto`, `go-jose`, cfssl, 
`cloudflare/circl`.
    The TLS server in `engine/daemon/hosts.go:75` and the Splunk logger in
    `engine/daemon/logger/splunk/splunk.go:172` are missing an explicit
    `tls.MinVersion` (semgrep `missing-ssl-minversion`); Go 1.22 defaults to
    TLS 1.2 as the minimum, so this is not currently exploitable but should
    be tightened to `tls.VersionTLS13` upstream.
  - `math/rand` is used in 6 non-cryptographic contexts
    (names-generator, networkdb cluster ID, resolver, graphtest, random
    test-image generator) - none of these are security-sensitive.
  - Docker Content Trust (Notary) provides signed-tag repositories via the
    `docker-trust` plugin. No certificate-validation issues were flagged.

- Use of temp files
  - No predictable `/tmp` filenames found in shipped code. The only `tmp`
    hit is `contrib/syscall-test/acct.c:10` (`acct("/tmp/t")`), which is
    test-only and not shipped.

- Use of networking
  - The daemon listens on `/var/run/docker.sock` (Unix socket, group
    `docker`, mode 0660) by default; the optional TCP/REST API is not
    enabled by default and must be explicitly configured by the admin
    (https://docs.docker.com/engine/daemon/remote-access/). All container
    input is treated as untrusted. No external endpoints are exposed by
    default. The userland `docker-proxy` handles port forwarding from the
    host into containers (and is the binary with the hardening gap noted
    below). No web-application debug-output concerns.

- Use of WebKit
  - None.

- Use of PolicyKit
  - None.

- Any significant cppcheck results
  - 8 findings, all in vendored Darwin cgo code
    (`process_collector_mem_cgo_darwin.c`: uninitialised `info`/`b_info`)
    plus one encoding-error on `engine/vendor/.../goid_go1.3.c`. None of
    this code is compiled on Linux; no significant Linux-side findings.

- Any significant Coverity results
  - Not run (no `coverity.txt` was produced for this audit, as we are having
    infrastructure issues on its server).

- Any significant shellcheck results
  - 638 warnings, the overwhelming majority in vendored codegen scripts
    (`debian/extra/vendor/golang.org/x/sys/{plan9,unix}/mk*.sh`,
    `engine/vendor/.../mk*.sh`) - these generate Go source from kernel
    headers and are not shipped. The only shipped hits are minor style
    issues in `debian/get-orig-source.sh` (unquoted variables, `if mycmd; $?`
    pattern) and `debian/docker.io.postinst` (unquoted variables in the ZFS
    migration block - worth a follow-up but not a security issue as inputs
    are controlled).

- Any significant bandit results
  - 37 LOW findings, all in `tini/test/*.py` (subprocess usage, `assert`,
    one `random` import). Test-only; no shipped Python code is affected.

- Any significant govulncheck results
  - govulncheck did not run (no top-level `go.mod`); see `osv-scanner`
    below for the vendored-dependency vulnerability scan.

- Any significant Semgrep results
  - 97 findings. After filtering test fixtures and CI:
      * 5 private-key detections - all test fixtures
        (`engine/client/testdata/key.pem`, 
`engine/integration/testdata/https/*`,
        `engine/integration-cli/fixtures/https/*-rogue-key.pem`). Not shipped.
      * 6 `math/rand` usages - non-crypto, see cryptography section.
      * 2 `missing-ssl-minversion` - see cryptography section.
      * 1 `decompression-bomb` (`engine/daemon/pkg/plugin/backend_linux.go:813`)
        - plugin pull path; worth a follow-up to add an `io.CopyN` size
        limit, but plugin installation is an admin-controlled operation.
      * ~20 `dangerous-exec-command` - see "Processes spawned".
      * 7 `missing-unlock-before-return` / `missing-runlock-on-rwmutex`
        (`engine/daemon/events/events.go:59`,
        `engine/daemon/internal/stream/bytespipe/bytespipe.go:183`,
        `engine/daemon/libnetwork/drivers/overlay/ov_network.go:192,196,628`,
        `engine/internal/testutil/helpers.go:136`,
        `engine/daemon/logger/loggerutils/logfile.go:396`). These look like
        false positives given Go's `defer` semantics but are worth an
        upstream follow-up.
      * 3 `invalid-usage-of-modified-variable`
        (`image_builder.go:161`, `osallocator_windows.go:73`,
        `volume/service/store.go:774`) - potential nil-deref on error paths,
        worth upstream follow-up.
      * GitHub Actions `${{...}}` injection findings 
(`.github/workflows/.vm.yml`,
        `.windows.yml`, `.test.yml`) are CI-only and not shipped.
      * `docker-compose` privileged/no-new-privileges/read-only findings are
        in compose test fixtures, not shipped defaults.

Vendored dependency vulnerabilities (osv-scanner)
  - 28 known vulnerabilities across 15 packages, 27 of which are fixable:
      * CVE-2026-1229 (CVSS 9.8) in `engine/vendor/github.com/...` (no fixed
        version listed).
      * google.golang.org/grpc 1.76.0 -> 1.79.3 (GO-2026-4762, CVSS 9.1).
      * github.com/containerd/containerd/v2 2.2.0 -> 2.2.5 (6 advisories,
        up to CVSS 8.7).
      * github.com/moby/buildkit 0.26.2 -> 0.28.1 (8.4, 8.2).
      * golang.org/x/crypto 0.45.0 -> 0.52.0 (5 advisories).
      * golang.org/x/net 0.47.0 -> 0.55.0 (2 advisories).
      * go.opentelemetry.io/otel* 1.38.0 -> 1.41/1.43.
      * github.com/cloudflare/circl 1.6.1 -> 1.6.3 (2.9).
      * github.com/in-toto/in-toto-golang 0.9.0 -> 0.11.0 (4.1).
      * github.com/aws/aws-sdk-go-v2 (eventstream/cloudwatchlogs) (5.9).
  - Most of these are expected to be cleared by packaging upstream 29.5.x
    (already requested by the MIR reviewer in comment #7 of the bug).

Hardening (binaries.txt + lintian)
  - dockerd: PIE yes, RELRO yes, Fortify yes; no stack protector, no
    stack-clash protection, no CFI. This is largely an artefact of the Go
    runtime, which manages its own stack and control flow.
  - docker (CLI): PIE yes, RELRO yes; no stack protector / stack-clash / CFI
    (same Go-runtime caveat).
  - docker-init (tini): statically linked by design (lintian
    `statically-linked-binary`); has stack-clash protection and CFI.
  - docker-trust: statically linked by design.
  - docker-proxy (C, libnetwork userland proxy, runs as root): **no PIE, no
    RELRO, no immediate binding, no stack protector, no stack-clash, no CFI**.
    Lintian flags `hardening-no-pie` and `hardening-no-relro`. This is the
    one genuine hardening gap and is worth a follow-up with the Server team
    (the binary is built via the upstream cgo/libnetwork Makefile, which
    does not pick up the Debian build flags).

General comments
  - The package is well-structured for a container runtime: no setuid/sgid,
    no sudo/polkit/udev/cron, no external network endpoints by default,
    AppArmor profile shipped, sane maintainer scripts with clean cleanup
    paths, debconf-driven daemon restarts on upgrade.
  - The principal security exposure is inherent to any container runtime
    (root daemon managing namespaces/cgroups/seccomp), mitigated by the
    upstream hardening features (seccomp profiles, AppArmor, namespaces,
    cgroups, user-namespace remapping option).
  - The principal audit-specific concerns are: (1) the set of vendored-Go
    CVEs flagged by osv-scanner, which the planned 29.5.x upload should
    clear; (2) the `docker-proxy` hardening gap; and (3) a handful of
    low-severity upstream follow-ups (missing TLS MinVersion, a couple of
    semgrep concurrency false-positives, plugin-pull decompression limit).
    None of these rise to the level of blocking promotion to main.

Security team ACK for promoting docker.io-app to main
  - ACK, conditional on packaging upstream 29.5.x (or newer) to
    clear the vendored-Go CVEs flagged by osv-scanner
    (in particular the CVSS 9.1/9.8 issues in
    grpc/CVE-2026-1229/containerd/buildkit/x-crypto/x-net),
    with a re-run of osv-scanner against the promoted version.
  - Recommended (non-blocking) follow-ups for the Server team to raise
    upstream:
      * Add explicit `tls.MinVersion: tls.VersionTLS13` in
        `engine/daemon/hosts.go` and `engine/daemon/logger/splunk/splunk.go`.
      * Add an `io.CopyN` size cap on plugin pull in
        `engine/daemon/pkg/plugin/backend_linux.go:813`.
      * Build `docker-proxy` with PIE/RELRO/stack-protector enabled
        (`hardening-no-pie`, `hardening-no-relro` lintian flags).
      * Tidy the minor shellcheck findings in `debian/get-orig-source.sh`
        and the `postinst` ZFS migration block.

** CVE added: https://cve.org/CVERecord?id=CVE-2026-1229

** Changed in: docker.io-app (Ubuntu)
     Assignee: Ubuntu Security Team (ubuntu-security) => (unassigned)

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2140335

Title:
  [MIR] Promote docker.io-app

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/docker.io-app/+bug/2140335/+subscriptions


-- 
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to