Skip to content

ECS Exec session transcript logging broken on script command (util-linux) ≥ 2.39 — script: unexpected number of arguments #667

Description

@TonyLovesDevOps

Summary

ssm-session-worker calls script(1) with a legacy positional argument order that was
rejected starting in util-linux v2.39. ECS Exec session logging silently fails on any
container image shipping util-linux ≥ 2.42. This is distinct from #653 (missing binary) —
the binary is present but the invocation is wrong.

Error

From /var/log/amazon/ssm/errors.log inside the container:

Failed to generate transcript with the following errors:
exit status 1: script: unexpected number of arguments
exit status 1: script: unexpected number of arguments

No log stream is created in CloudWatch and no session log is uploaded anywhere. Sessions
appear to succeed but produce no audit log.

Root cause

generateLogData in shell_unix.go lines 347–356
calls script in the legacy BSD positional form:

// Form A (line 347): script <logfile> -c "<command>"
cmdWithFlag := exec.CommandContext(ctx, startRecordSessionCmd, p.logger.logFilePath, scriptFlag, loggerCmd)

// Form B (line 356, fallback): script <logfile> cat <ipcfile>
cmdWithoutFlag := exec.CommandContext(ctx, startRecordSessionCmd, p.logger.logFilePath, catCmd, p.logger.ipcFilePath)

util-linux commit ec96a89
("script: abort if unused arguments are given", 21 Nov 2022, released in v2.39) tightened
argument parsing. The situation by version:

Form util-linux 2.39.x util-linux 2.42+
script <file> -c "cmd" (Form A)
script <file> prog args (Form B)

Both forms fail on 2.42+. Form B fails on all versions ≥ 2.39.

Reproducing the exact SSM agent invocations:

$ docker run --rm ubuntu:24.04 bash -c '
  apt-get install -y -q util-linux > /dev/null 2>&1
  echo "data" > /tmp/ipc

  echo "=== Form A (SSM primary): script <logfile> -c <cmd> ==="
  script /tmp/test.log -c "echo hello" 2>&1 || true

  echo "=== Form B (SSM fallback): script <logfile> cat <file> ==="
  script /tmp/test.log cat /tmp/ipc 2>&1 || true

  echo "=== Note: -- separator requires 2.41+, also fails here ==="
  script -q /tmp/test.log -- cat /tmp/ipc 2>&1 || true
'

=== Form A (SSM primary): script <logfile> -c <cmd> ===
Script started, output log file is '/tmp/test.log'.
hello
Script done.

=== Form B (SSM fallback): script <logfile> cat <file> ===
script: unexpected number of arguments
Try 'script --help' for more information.

=== Note: -- separator requires 2.41+, also fails here ===
script: unexpected number of arguments
Try 'script --help' for more information.

Form A happens to still work on 2.39.x because options after the filename are still
accepted, but it fails on 2.42+ (Wolfi/Chainguard). Form B fails on all versions ≥ 2.39.

Fix

Update generateLogData in shell_unix.go
to use -c with the logfile last. This satisfies util-linux's strict parser (≥ 2.39)
while remaining valid on all older versions, since pre-2.39 accepted options in any order:

// Form A — was: script <logfile> -c "<command>"
cmdWithFlag := exec.CommandContext(ctx, startRecordSessionCmd, "-q", "-c", loggerCmd, p.logger.logFilePath)

// Form B — was: script <logfile> cat <ipcfile>
cmdWithoutFlag := exec.CommandContext(ctx, startRecordSessionCmd, "-q", "-c",
    fmt.Sprintf("%s %s", catCmd, p.logger.ipcFilePath), p.logger.logFilePath)

Workaround

Place the following shim at /usr/local/bin/script (ahead of /usr/bin/script in $PATH):

#!/bin/sh
# Translates amazon-ssm-agent's legacy script(1) invocation to util-linux >= 2.39 syntax.
# Note: the -- separator requires 2.41+, so we normalise both forms to -c.
file=$1
shift
if [ "$1" = "-c" ]; then
    exec /usr/bin/script -q -c "$2" "$file"
fi
exec /usr/bin/script -q -c "$*" "$file"

Environment

  • ECS Exec (Session Manager) with CloudWatch Logs transcript logging
  • Container: Wolfi/Chainguard (util-linux 2.42); also reproduced on Ubuntu 24.04 (util-linux 2.39.3)
  • amazon-ssm-agent: 3.3.0.0
/managed-agents/execute-command/amazon-ssm-agent --version
SSM Agent version: 3.3.0.0

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