pjfanning opened a new pull request, #3505:
URL: https://github.com/apache/pekko/pull/3505

   ### Motivation
   Three sites parse HOCON that arrived in a message, using the default parse 
options:
   
   | Site | Reached by |
   | --- | --- |
   | `ClusterMessageSerializer:302` — `deserializeInitJoin` | `InitJoin`, from 
a node that has not joined |
   | `ClusterMessageSerializer:313` — `deserializeInitJoinAck` | `InitJoinAck`, 
from a claimed seed node |
   | `MiscMessageSerializer:549` — `deserializeConfig` | any `Config` payload 
from an associated peer |
   
   HOCON `include` directives are resolved by the *parser*, not by `resolve()`, 
so they take
   effect as soon as the message is deserialized — before `ClusterDaemon` forms 
any opinion
   about the sender. `InitJoin` is accepted in the `uninitialized` state
   (`ClusterDaemon.scala:501`), so for that one the sender need not be a 
cluster member at all.
   
   That gives a peer a blind SSRF primitive from inside the node (`include 
url("http://…";)`
   reaches addresses the sender cannot) and a forced read of local files and 
classpath
   resources.
   
   I checked the behaviour against config 1.4.6 rather than assuming it, and 
the result changed
   the shape of the fix. A plain `ConfigIncluder` is **not** enough — the 
parser falls back to
   its own handling, which does read the resource, for any typed form the 
includer does not
   implement:
   
   ```
   include form            defaults   plain ConfigIncluder   all four interfaces
   include file(...)       reads      reads                  blocked
   include required(file)  reads      reads                  blocked
   include url(...)        reads      reads                  blocked
   include classpath(...)  reads      reads                  blocked
   include "..."           no-op      blocked                blocked
   ```
   
   (Bare `include "..."` is already inert here: `SimpleIncluder` resolves it 
relative to the
   including source, and a string has none.)
   
   ### Modification
   Add `org.apache.pekko.serialization.WireConfig` (`@InternalApi`), which 
parses with
   `ConfigParseOptions.defaults().setIncluder(...)` where the includer resolves 
every form to an
   empty object. It implements `ConfigIncluder`, `ConfigIncluderFile`, 
`ConfigIncluderURL` and
   `ConfigIncluderClasspath` — all four are needed, per the table above. Route 
the three sites
   through it.
   
   Every serializer writes config with `ConfigRenderOptions.concise` 
(`MiscMessageSerializer:172`,
   `ClusterMessageSerializer:401`), which renders JSON and cannot produce an 
`include`, so a
   well-behaved sender loses nothing and no rolling-upgrade path is affected.
   
   Includes are dropped silently rather than logged. `deserializeConfig` is on 
the ordinary
   per-message path, so a peer-triggerable log line there is its own small 
flooding surface, and
   the drop is already fail-safe. Happy to add a `LogMarker.Security` debug 
line if reviewers
   would rather have the signal.
   
   ### Result
   Deserializing a message no longer reads local files or classpath resources, 
or issues
   outbound requests, on behalf of the sender.
   
   ### Tests
   - `sbt "actor-tests/testOnly org.apache.pekko.serialization.WireConfigSpec"` 
— 7 passed: ordinary
     HOCON and concise-rendered config still parse; `file`, `required(file)`, 
`url` and `classpath`
     includes all resolve to nothing; and one test asserts the *default* parser 
does resolve all
     three, so the others are testing the change rather than an inert directive
   - `sbt "cluster/testOnly 
org.apache.pekko.cluster.protobuf.ClusterMessageSerializerSpec"` — 10 passed,
     including a new test covering both `InitJoin` and `InitJoinAck`
   - `sbt "remote/testOnly 
org.apache.pekko.remote.serialization.MiscMessageSerializerSpec"` — 104 passed,
     including a new test for the `Config` payload
   - Both new module tests were checked to discriminate by reverting the 
production change and
     re-running: each fails with `true did not equal false`
   - `sbt "actor/mimaReportBinaryIssues" "remote/mimaReportBinaryIssues" 
"cluster/mimaReportBinaryIssues"` — no issues
   - `sbt scalafmtAll headerCreateAll` — no changes
   
   ### References
   None. `WireConfig.scala` is new code and carries the standard ASF header.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to