Skip to content

pre-start scripts fails when JAVA_OPTS contains special characters #1259

@stokpop

Description

@stokpop

When JAVA_OPTS is defined in a CF manifest using a YAML block scalar (>), CF may deliver the value with literal newlines, or the value may contain pipe characters (|) as part of javaagent options:

env:
  JAVA_OPTS: >
    -javaagent:$HOME/BOOT-INF/lib/jfr-exporter.jar=enableExecutorMBeans|disableMyFeature
    -XX:+UseZGC
    -XX:+AlwaysPreTouch
    -XX:-ZUncommit
    -XX:MaxDirectMemorySize=256m

The profile.d/00_java_opts.sh script uses sed to substitute $JAVA_OPTS, $HOME and $DEPS_DIR into each .opts file. The sed delimiter is |, and the replacement string is not sanitised, so the command fails when the value contains | or newlines:

[APP/PROC/WEB/0] OUT Invoking pre-start scripts.
[APP/PROC/WEB/0] ERR sed: -e expression #1, char 257: unterminated `s` command
[APP/PROC/WEB/0] ERR sed: -e expression #1, char 257: unterminated `s` command
[APP/PROC/WEB/0] ERR sed: -e expression #1, char 257: unterminated `s` command
[APP/PROC/WEB/0] ERR sed: -e expression #1, char 257: unterminated `s` command

The error repeats once per .opts file. Because the script has no set -e, execution continues — but all opts content is dropped and the JVM starts with an empty JAVA_OPTS: no memory limits, no agents.

Additionally, & and \ in JAVA_OPTS are interpreted as sed replacement metacharacters, causing silent data corruption instead of a visible error.

The ERR lines are only visible in CF application logs; there is no staging failure or app crash that directly points to this cause.

Impact

All JVM flags are silently dropped at startup:

  • Buildpack-calculated memory settings (-Xmx, -Xss, -XX:MaxMetaspaceSize) absent → OOM / GC thrashing
  • Java agents not attached → no APM/tracing instrumentation
  • -Djava.security.properties missingCloudFoundryContainerProvider not registered → CF system certificates not loaded into JVM truststore → TLS handshake failures: (certificate_unknown) No trusted certificate found

The last point is tricky to diagnose: the connection between the sed error lines at startup and TLS failures later at runtime is not obvious.

Suggestions

  • Avoid sed for variable substitution in the assembly script; use bash parameter expansion instead, which has no special-character restrictions
  • Normalize JAVA_OPTS to a single line before substitution to handle YAML block scalar newlines
  • Consider adding set -e to the script so that any failure causes a hard stop rather than continuing with an empty or corrupt JAVA_OPTS

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