Contain public resource output paths - #10378
Conversation
|
What's the actual bug or feature you're addressing here? If I'm reading it right, this looks like validation that the project's source isn't maliciously reading other files on disk as if they are source - but specific only to the codeserver, rather than the compiler or running tests? |
|
The bug this addresses is path traversal on output writes, not source reads. Public resource path names (and other output paths) can contain segments like It’s also not CodeServer-only:
So the shared write-path hardening is in Happy to broaden coverage further if there’s another write sink you think should get the same treatment. |
| test_suite( | ||
| name = "tests", | ||
| tests = [ | ||
| ":LauncherDirTest", |
There was a problem hiding this comment.
The Bazel build files are not used, no need to update them.
Understood - but my question is where is the path read from such that output is written to the incorrect location? Or does the compiler generate
How can that happen, specifically, in a real project? Public resources are resources in a directory specified by a You didn't file or link an issue to go with this, so it seems like you're speculating based on code that looks wrong at a glance outside the context of the rest of the project. I could imagine that a Generator might be able to achieve this case, but someone would need to go out of their way to do it that way, and I'm not sure how we reasonably guard against that without breaking existing code. If that is the specific use case you're after, it would be far better to move that validation closer to where the path is emitted so that the user gets a stack trace that reflects the issue. |
|
Fair question — thanks for pushing on the concrete path. Where the path comes from (not the compiler inventing For public resources, path names are the rerooted classpath resource paths from So the realistic case is a JAR/ZIP on the compile classpath whose entry name starts with the module’s
That’s classic zip-slip into the output tree. A normal on-disk
That path is not limited to public resources. On validating closer to emission Agreed for the Generator/Linker case: rejecting at Also noting @zbynek’s comment: Bazel Happy to add a small JAR-based regression that packs a |
|
Follow-up pushed:
Ant/JUnit |
168261f to
ae28dff
Compare
Reject escaping relative paths in OutputFileSet.openForWrite so Generator/Linker emissions fail at the emit API with a clear error, keep the directory canonicalization check as defense in depth, and revert the unused codeserver Bazel test_suite wiring.
ae28dff to
f2aaace
Compare
|
So to confirm, "The bug this addresses is path traversal on output writes, not source reads" actually means "yes, this is a bug with malicious sources". I agree this is a plausible issue, but this is what I was hoping for you to clarify in the issue, in the PR title/description, or when I asked the first time. If the preexisting unit test confirms that the behavior works, (ping @jnehlmeier, the author of that test), perhaps we shouldn't be changing this? Instead, when there is an issue of unsafe inputs, we should validate the inputs themselves, right? For example, The If a classpath jar has apparently malicious contents, warning when we find the issue with a specific pointer to the jar in question seems more appropriate than logging where we would have written the output - if there is something malicious on the classpath, it should be removed outright. That said, if you've already included something malicious like this on the classpath and included its .gwt.xml, they could have just written a Generator that runs arbitrary code at compile time, so its a weird way to try to attack. -- We already have a few tests that use checked-in jars/zips for resource scanning and such - ClassPathEntryTest, ResourceOracleImplRealClasspathTest, and ResourceOracleImplTest each extend from AbstractResourceOrientedTestBase which offers helper methods to find these existing test jars. You might want to model any tests off of this, to demonstrate detection and handling. |
|
The test exists because there was a regression long ago which is discussed in #8483 However in the linked issue there was already discussion within the Google team to restrict such paths, either completly or only allowing them within a sane boundery like the current project. So they asked back why But even if disallowed a malicious library can still literally to anything on your host. As @niloc132 pointed out you usually have to inherit a GWT module and once you do that, this GWT module can mess with public resource paths but also replace a linker or generator and sneak in additional malicious code that uses java.nio to write anywhere. It is similar to adding a new maven or gradle plugin to the build. You have to trust that new external library and in the best case verify its hash before each build if you use a build system that potentially downloads that library automatically. There is only one way without inheriting a GWT module manually and that is if a classpath jar provides a GWT module that GWT SDK also provides. In that case classpath ordering decides which GWT module will be loaded. GWT could potentially check if GWT SDK modules have been indeed loaded from GWT SDK jars but in general it is much better to secure your build via your build tool so you can trust your libraries based on signatures. |
|
Any more thoughts here or should we close this? |
|
Let's close this, can always reopen if something changes. |
Contain public resource output paths
Public resource paths can be supplied by classpath resources and are later written into compiler and CodeServer output directories. This change resolves output paths against the intended output root and rejects any path that canonicalizes outside that root before creating parent directories or writing bytes.
Changes:
OutputFileSetOnDirectorywrites insidedir + prefix.Validation:
git diff --checkant dev -Dtarget=test -Dgwt.junit.testcase.dev.core.includes="**/OutputFileSetOnDirectoryTest.class"ant codeserver -Dtarget=test -Dtest.dev.disable=trueNo linked issue.