Skip to content

Manual benchmark and formatter inputs are interpreted as shell syntax #1213

Description

@fegge

The manual EC2 benchmark workflow exposes free-form inputs that are intended to
be benchmark configuration, compiler options, and extra test arguments. The
workflow forwards those values into shell run blocks without first placing
them behind an argument boundary. A repository user with permission to dispatch
the manual benchmark workflow, or a maintainer who runs it with values copied
from an untrusted request, can therefore cause shell metacharacters in those
fields to execute on privileged CI runners.

The dispatchable workflow exposes cflags, archflags, ldflags,
bench_extra_args, and compiler as free-form inputs and forwards them into
the reusable EC2 benchmark workflow.

      cflags:
        description: Custom CFLAGS for compilation
        default:
      archflags:
        description: Custom ARCH flags for compilation
        default: ''
      ldflags:
        description: Custom LDFLAGS for linking
        default: ''
# ...
      bench_extra_args:
        description: Additional command line to be appended to `tests bench` script
        default: ''
      compiler:
        description: Compiler to use. When unset, default nix shell is used.
        default: ''
# ...
      cflags: ${{ inputs.cflags }}
      archflags: ${{ inputs.archflags }}
      ldflags: ${{ inputs.ldflags }}
# ...
      bench_extra_args: ${{ inputs.bench_extra_args }}
      compiler: ${{ inputs.compiler }}

Figure X.1: The manual EC2 benchmark workflow accepts and forwards free-form benchmark inputs (mldsa-native/.github/workflows/bench_ec2_any.yml#L29-L69)

The reusable workflow writes the compiler input directly into a shell command
that appends to $GITHUB_ENV. GitHub Actions substitutes the expression before
Bash parses the script, so characters such as quotes, semicolons, and command
substitutions are interpreted as shell syntax.

      - name: Set compiler
        run: |
          echo "CC=${{ inputs.compiler }}" >> "$GITHUB_ENV"

Figure X.2: The reusable benchmark workflow interpolates compiler into a shell command (mldsa-native/.github/workflows/bench_ec2_reusable.yml#L182-L184)

The benchmark action also interpolates forwarded benchmark options directly
into two ./scripts/tests bench command lines. These jobs run on EC2-backed
self-hosted runners and use repository tokens for benchmark publication and
pull-request updates, so command execution in this path can affect CI state.

        ./scripts/tests bench -c ${{ inputs.perf }} --cross-prefix="${{ inputs.cross_prefix }}" \
              --cflags="${{ inputs.cflags }} ${{ inputs.archflags }}" \
              --ldflags="${{ inputs.ldflags }}" \
              --opt=$([[ ${{ inputs.opt }} == "false" ]] && echo "no_opt" || echo "opt")  \
              -v --output=output.json ${{ inputs.bench_extra_args }}

        ./scripts/tests bench --components -c ${{ inputs.perf }} --cross-prefix="${{ inputs.cross_prefix }}" \
              --cflags="${{ inputs.cflags }} ${{ inputs.archflags }}" \
              --ldflags="${{ inputs.ldflags }}" \
              --opt=$([[ ${{ inputs.opt }} == "false" ]] && echo "no_opt" || echo "opt")  \
              -v  ${{ inputs.bench_extra_args }}

Figure X.3: The benchmark action interpolates free-form benchmark inputs into shell commands (mldsa-native/.github/actions/bench/action.yml#L80-L91)

The same data-to-code boundary appears in local developer tooling. The
formatter reads tracked filenames from Git and substitutes them into sh -c
script text. A contributor can place shell metacharacters in a tracked filename
on an untrusted branch, and a maintainer who runs the formatter before review
can execute that filename as shell syntax.

git ls-files -- ":/*.c" ":/*.h" | xargs -P "$nproc" -I {} sh -c '
  # Ignore symlinks
  if [[ ! -L {} ]]; then
    clang-format -i {}
  fi'
# ...
  git ls-files -- ":/" ":/!:Makefile" ":/!:**/Makefile" ":/!:**/Makefile.*" ":/!:Makefile.*" ":/!:*.mk" ":/!:*.patch" ":/!:nix/valgrind/*.txt" | xargs -P "$nproc" -I {} sh -c '
    if [ ! -L {} ] && grep -Pq '"'"'\t'"'"' "{}"; then
      tmp=$(mktemp)
      expand -t 4 "{}" > "$tmp" && mv "$tmp" "{}"
      echo "{}"
    fi'

Figure X.4: The formatter substitutes tracked filenames into sh -c script text (mldsa-native/scripts/format#L63-L77)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions