From a51e570e0c7c7e73b2be0315a95535c87d2c30de Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 30 Aug 2021 14:46:54 +1000 Subject: [PATCH] Alternate fix for #6497 Signed-off-by: Greg Wilkins --- .../maven/plugin/MavenWebAppContext.java | 8 ++++---- .../server/AllowedResourceAliasChecker.java | 12 +++++++---- .../jetty/server/SameFileAliasChecker.java | 2 +- .../SymlinkAllowedResourceAliasChecker.java | 20 ++++++++++++++++--- .../handler/AllowSymLinkAliasChecker.java | 2 +- .../jetty/server/handler/ContextHandler.java | 20 +++++++++---------- .../ContextHandlerGetResourceTest.java | 4 ++-- .../eclipse/jetty/webapp/WebAppContext.java | 12 +++++------ 8 files changed, 49 insertions(+), 31 deletions(-) diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenWebAppContext.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenWebAppContext.java index 74a60614ba0a..ee81ee465b59 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenWebAppContext.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenWebAppContext.java @@ -351,18 +351,18 @@ public void doStop() throws Exception } @Override - public Resource getResource(String uriInContext) throws MalformedURLException + public Resource getResource(String pathInContext) throws MalformedURLException { Resource resource = null; // Try to get regular resource - resource = super.getResource(uriInContext); + resource = super.getResource(pathInContext); // If no regular resource exists check for access to /WEB-INF/lib or // /WEB-INF/classes - if ((resource == null || !resource.exists()) && uriInContext != null && _classes != null) + if ((resource == null || !resource.exists()) && pathInContext != null && _classes != null) { // Canonicalize again to look for the resource inside /WEB-INF subdirectories. - String uri = URIUtil.canonicalPath(uriInContext); + String uri = URIUtil.canonicalPath(pathInContext); if (uri == null) return null; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AllowedResourceAliasChecker.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AllowedResourceAliasChecker.java index 4a5377730630..5132c94ba048 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AllowedResourceAliasChecker.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AllowedResourceAliasChecker.java @@ -85,7 +85,7 @@ protected void doStop() throws Exception } @Override - public boolean check(String uri, Resource resource) + public boolean check(String pathInContext, Resource resource) { // The existence check resolves the symlinks. if (!resource.exists()) @@ -121,8 +121,12 @@ protected boolean isAllowed(Path path) throws IOException for (Path protectedPath : _protected) { - if (Files.exists(protectedPath, FOLLOW_LINKS) && Files.isSameFile(path, protectedPath)) - return false; + if (Files.exists(protectedPath)) + { + protectedPath = protectedPath.toRealPath(FOLLOW_LINKS); + if (Files.exists(protectedPath) && Files.isSameFile(path, protectedPath)) + return false; + } } path = path.getParent(); @@ -151,7 +155,7 @@ protected Path getPath(Resource resource) public String toString() { return String.format("%s@%x{base=%s,protected=%s}", - AllowedResourceAliasChecker.class.getSimpleName(), + this.getClass().getSimpleName(), hashCode(), _base, Arrays.asList(_contextHandler.getProtectedTargets())); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/SameFileAliasChecker.java b/jetty-server/src/main/java/org/eclipse/jetty/server/SameFileAliasChecker.java index 406b6a4148ee..8185766d46ee 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/SameFileAliasChecker.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/SameFileAliasChecker.java @@ -47,7 +47,7 @@ public class SameFileAliasChecker implements AliasCheck private static final Logger LOG = LoggerFactory.getLogger(SameFileAliasChecker.class); @Override - public boolean check(String uri, Resource resource) + public boolean check(String pathInContext, Resource resource) { // Only support PathResource alias checking if (!(resource instanceof PathResource)) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/SymlinkAllowedResourceAliasChecker.java b/jetty-server/src/main/java/org/eclipse/jetty/server/SymlinkAllowedResourceAliasChecker.java index abce7d052cf1..960c6345824f 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/SymlinkAllowedResourceAliasChecker.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/SymlinkAllowedResourceAliasChecker.java @@ -13,6 +13,7 @@ package org.eclipse.jetty.server; +import java.nio.file.Files; import java.nio.file.Path; import org.eclipse.jetty.server.handler.ContextHandler; @@ -36,7 +37,7 @@ public SymlinkAllowedResourceAliasChecker(ContextHandler contextHandler) } @Override - public boolean check(String uri, Resource resource) + public boolean check(String pathInContext, Resource resource) { // The existence check resolves the symlinks. if (!resource.exists()) @@ -46,15 +47,28 @@ public boolean check(String uri, Resource resource) if (path == null) return false; + String[] segments = pathInContext.split("/"); + Path fromBase = _base; + try { - Path link = path.toRealPath(NO_FOLLOW_LINKS); - return path.equals(link) ? isAllowed(path) : isAllowed(link); + for (String segment : segments) + { + fromBase = fromBase.resolve(segment); + if (!Files.exists(fromBase)) + return false; + if (Files.isSymbolicLink(fromBase)) + return true; + if (!isAllowed(fromBase)) + return false; + } } catch (Throwable t) { LOG.warn("Failed to check alias", t); return false; } + + return true; } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.java index bf807bd14b73..dd81bbb8f605 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.java @@ -41,7 +41,7 @@ public AllowSymLinkAliasChecker() } @Override - public boolean check(String uri, Resource resource) + public boolean check(String pathInContext, Resource resource) { // Only support PathResource alias checking if (!(resource instanceof PathResource)) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java index 5fe5f65f7c86..b95ad58cfeee 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java @@ -1920,14 +1920,14 @@ public Map getLocaleEncodings() /** * Attempt to get a Resource from the Context. * - * @param path the path within the resource to attempt to get + * @param pathInContext the path within the base resource to attempt to get * @return the resource, or null if not available. * @throws MalformedURLException if unable to form a Resource from the provided path */ - public Resource getResource(String path) throws MalformedURLException + public Resource getResource(String pathInContext) throws MalformedURLException { - if (path == null || !path.startsWith(URIUtil.SLASH)) - throw new MalformedURLException(path); + if (pathInContext == null || !pathInContext.startsWith(URIUtil.SLASH)) + throw new MalformedURLException(pathInContext); if (_baseResource == null) return null; @@ -1937,9 +1937,9 @@ public Resource getResource(String path) throws MalformedURLException // addPath with accept non-canonical paths that don't go above the root, // but will treat them as aliases. So unless allowed by an AliasChecker // they will be rejected below. - Resource resource = _baseResource.addPath(path); + Resource resource = _baseResource.addPath(pathInContext); - if (checkAlias(path, resource)) + if (checkAlias(pathInContext, resource)) return resource; return null; } @@ -3027,11 +3027,11 @@ public interface AliasCheck /** * Check an alias * - * @param path The path the aliased resource was created for + * @param pathInContext The path the aliased resource was created for * @param resource The aliased resourced * @return True if the resource is OK to be served. */ - boolean check(String path, Resource resource); + boolean check(String pathInContext, Resource resource); } /** @@ -3042,7 +3042,7 @@ public interface AliasCheck public static class ApproveAliases implements AliasCheck { @Override - public boolean check(String path, Resource resource) + public boolean check(String pathInContext, Resource resource) { return true; } @@ -3055,7 +3055,7 @@ public boolean check(String path, Resource resource) public static class ApproveNonExistentDirectoryAliases implements AliasCheck { @Override - public boolean check(String path, Resource resource) + public boolean check(String pathInContext, Resource resource) { if (resource.exists()) return false; diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java index 4d055bf4609d..51c952a6dd25 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java @@ -114,12 +114,12 @@ public static void beforeClass() throws Exception } @Override - public boolean check(String path, Resource resource) + public boolean check(String pathInContext, Resource resource) { if (allowAliases.get()) return true; if (allowSymlinks.get()) - return symlinkcheck.check(path, resource); + return symlinkcheck.check(pathInContext, resource); return allowAliases.get(); } }); diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java index a85ef9354c04..14c1118335c8 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java @@ -395,23 +395,23 @@ public void setClassLoader(ClassLoader classLoader) } @Override - public Resource getResource(String uriInContext) throws MalformedURLException + public Resource getResource(String pathInContext) throws MalformedURLException { - if (uriInContext == null || !uriInContext.startsWith(URIUtil.SLASH)) - throw new MalformedURLException(uriInContext); + if (pathInContext == null || !pathInContext.startsWith(URIUtil.SLASH)) + throw new MalformedURLException(pathInContext); MalformedURLException mue = null; Resource resource = null; int loop = 0; - while (uriInContext != null && loop++ < 100) + while (pathInContext != null && loop++ < 100) { try { - resource = super.getResource(uriInContext); + resource = super.getResource(pathInContext); if (resource != null && resource.exists()) return resource; - uriInContext = getResourceAlias(uriInContext); + pathInContext = getResourceAlias(pathInContext); } catch (MalformedURLException e) {