Skip to content

Sweep parameter values are interpolated unquoted into /etc/profile.d — a value containing a quote or $ corrupts the sweep environment #531

Description

@scttfrdmn

Severity: medium — a legal parameter value breaks the env file for the whole instance

pkg/launcher/bootstrap.go:531-536 builds the sweep environment by appending shell source
lines, one per spawn:param:* tag:

echo "$PARAM_TAGS" | while IFS=$'\t' read -r key value; do
    if [[ $key == spawn:param:* ]]; then
        param_name=${key#spawn:param:}
        echo "export PARAM_${param_name}=\"${value}\"" >> /etc/profile.d/spawn-params.sh
    fi
done

${value} goes in raw, inside double quotes. So for a param file row like

params:
  - instance_type: c7g.16xlarge
    mdp_flags: -maxh 0.5 -notunepme
    label: run "A"
    prefix: $HOME/out

the generated /etc/profile.d/spawn-params.sh contains

export PARAM_label="run "A""      # quoting broken
export PARAM_prefix="$HOME/out"   # expanded at source time, not the literal

/etc/profile.d/*.sh is sourced by every login shell, so the workload sees a value it never set
(PARAM_prefix becomes /root/out or /home/ec2-user/out), and a value containing a double
quote mangles that line and possibly the next.

Three distinct failures from the same line:

value result
run "A" quoting broken; PARAM_label is not what was written
$HOME/out expanded on the instance at source time
a`hostname`b command substitution runs
value containing a newline the tag stores it, read -r splits it, the rest becomes a stray line

The values come from the user's own param file, so this is not a privilege boundary — it is a
correctness bug, and a $ in a path or flag string is an entirely ordinary thing to sweep over.
It is also the silent kind: nothing fails, the workload just runs with a different value than
the manifest says it did, which is a reproducibility problem as much as a bug.

Expected behaviour

Emit the value in a form the shell cannot reinterpret. Options:

  1. Single-quote and escape embedded single quotes: export PARAM_x='...'"'"'...'. Cheap and
    exact for everything except a literal newline.
  2. Write the values with a quoted heredoc (<<'EOF') as KEY=VALUE pairs and have the profile
    script read them rather than export them as shell source.
  3. Reject values containing a newline at launch time, since a tag round-trip through
    --output text cannot represent them faithfully anyway.

(1) plus (3) is the smallest correct change.

Regression test to add

A Tier 0 sweep with label: run "A", prefix: $HOME/out and a backtick value; assert the
generated env file (or the spawn:param:* tags plus a shell-parse of the rendered script)
yields the literal strings. The assertion must be on the rendered value, not on the tag — the
tag is already correct today, which is what makes this easy to miss.

Found while fixing #526, whose fix rejects param keys that cannot be valid shell
identifiers for the same reason: export PARAM_on-complete="x" is not a line the shell accepts.
That fix covers the key side of this line only; the value side is untouched.

Related: #524, #525, #526, #530.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:launchlaunch path: instance-type, AMI, user-data, runbugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions