Skip to content

fix(docker): glibc_run.sh -d overwrites the tracked Dockerfile first line #241

Description

@coygeek

Summary

At revision 02da6aa26a44e5af2a67057876d7c6669a207f56, the -d path in glibc_run.sh rewrites line 1 of the tracked Dockerfile in place before building the Docker image. The edit occurs without a warning about the working-tree mutation, a prompt, a backup, a temporary copy, or a later restore.

On a pristine checkout, a requested glibc version greater than 2.33 changes Dockerfile:1 from from ubuntu:20.04 to from ubuntu:22.04. A version at or below 2.33 writes from ubuntu:20.04; that may leave the pristine file byte-identical, but it still overwrites any custom first line.

Steps to reproduce

On Linux with the script's prerequisites installed and Docker available:

git clone https://github.com/shellphish/how2heap
cd how2heap
git checkout 02da6aa26a44e5af2a67057876d7c6669a207f56
make malloc_playground
git status --short -- Dockerfile
./glibc_run.sh 2.39 ./malloc_playground -d -p
git diff -- Dockerfile

The initial status is clean for Dockerfile. The final diff shows Dockerfile:1 changed from from ubuntu:20.04 to from ubuntu:22.04. The -p option prevents the prepared target from being executed; it does not change the Docker preparation path.

As a red/green closure check, the same command should leave git diff --exit-code -- Dockerfile clean after the Docker build input is made temporary.

Expected behavior

The Docker preparation flow should leave the tracked Dockerfile unchanged. It can select the requested Ubuntu base image using a temporary Dockerfile passed with docker build -f, or otherwise preserve and restore the original bytes on both success and failure.

Actual behavior

glibc_run.sh:143-145 maps -d to DOCKER='X', and glibc_run.sh:198-200 then calls prep_in_docker "$GLIBC_VERSION". Inside that function, glibc_run.sh:87-92 selects Ubuntu 22.04 for versions greater than 2.33 and Ubuntu 20.04 otherwise. After the Docker availability check, glibc_run.sh:103 executes:

sed -i "1s/.*/from ubuntu:$UBUNTU_VERSION/" Dockerfile

The first subsequent message is building the how2heap_docker image! at glibc_run.sh:104, after the edit has already occurred. No later code restores Dockerfile, so a failure in docker build or docker run also leaves the rewritten first line in place.

Affected area

  • glibc_run.sh:85-108 (prep_in_docker)
  • glibc_run.sh:143-145 (-d argument handling)
  • glibc_run.sh:198-200 (call into Docker preparation)
  • Dockerfile:1 (tracked line rewritten in place)

Runtime or environment

  • Source revision: 02da6aa26a44e5af2a67057876d7c6669a207f56
  • Verification method: static source inspection; the script was not executed
  • Relevant path: Bash with the GNU sed -i behavior used by the Linux/Docker workflow
  • Reachability condition: the target file and earlier glibc preparation steps must succeed, and the Docker check at glibc_run.sh:95-100 must pass

Evidence

  • Dockerfile:1 is from ubuntu:20.04 at the verified revision.
  • The mutation is exactly at glibc_run.sh:103.
  • The accepted -d path sets DOCKER at glibc_run.sh:143-145 and reaches prep_in_docker at glibc_run.sh:198-200 after the script's earlier prerequisites succeed.
  • glibc_run.sh:21-28 describes -d only as building the debugging environment in Docker; it does not disclose that a tracked file is edited.
  • The complete script contains no backup, restore, prompt, temporary Dockerfile, or cleanup path for this edit. Its only reference to Dockerfile is the in-place sed command at line 103.
  • The build announcement at glibc_run.sh:104 is emitted after the edit and does not warn that the working tree was changed.

Impact

  • Any uncommitted customization of Dockerfile:1 is replaced without confirmation.
  • On the pinned pristine revision, selecting a glibc version greater than 2.33 leaves a tracked diff that can be staged accidentally with unrelated work.
  • The mutation happens before docker build, so later build or run failure does not roll it back.
  • Repeated runs with versions on opposite sides of 2.33 leave line 1 set by the most recent run; no previous first-line content is retained.
  • A run for a version at or below 2.33 may produce no Git diff when line 1 already contains from ubuntu:20.04; the destructive behavior remains observable when line 1 was customized.

Additional context

Root-cause classification: destructive in-place mutation of a tracked build input by a convenience wrapper.

A minimal patch can generate a temporary Dockerfile and pass it explicitly to Docker:

# Replace the in-place edit and docker build in prep_in_docker.
local dockerfile_tmp
dockerfile_tmp=$(mktemp) || return 1
trap 'rm -f "$dockerfile_tmp"' RETURN

sed "1s/.*/from ubuntu:$UBUNTU_VERSION/" Dockerfile >"$dockerfile_tmp" || return 1
echo "building the how2heap_docker image!"
docker build -f "$dockerfile_tmp" -t how2heap_docker .

glibc_run.sh:107 subsequently runs make clean all inside the container. Makefile:66 defines all, while Makefile:68-70 defines clean; neither target reads or edits Dockerfile. Passing a temporary file to docker build therefore isolates the fix from the existing Makefile build flow.

Maintainer checklist:

  • Run the 2.39 -d -p reproduction and confirm git diff --exit-code -- Dockerfile remains clean.
  • Repeat with a version at or below 2.33.
  • Put a custom first line in Dockerfile and confirm both successful and failed Docker builds preserve it byte-for-byte.
  • Confirm the generated image still uses Ubuntu 22.04 for versions greater than 2.33 and Ubuntu 20.04 otherwise.
  • Confirm the container still completes the make clean all flow.

Verifier notes

The underlying claim is confirmed, but the original draft needed three material corrections. Its clean-clone reproduction did not create ./malloc_playground, so glibc_run.sh:119-122 would exit before argument handling and never reach the edit. The reproduction now builds that target and adds -p to avoid executing it. The impact is also narrowed to replacement of the first line, and the Git-dirty claim is limited to cases where the selected Ubuntu line differs from the current content. Unverified runtime and severity statements were replaced with the static verification boundary requested for this review.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions