diff --git a/core/src/main/java/org/elasticsearch/node/Node.java b/core/src/main/java/org/elasticsearch/node/Node.java index 2508872eed1..103add62809 100644 --- a/core/src/main/java/org/elasticsearch/node/Node.java +++ b/core/src/main/java/org/elasticsearch/node/Node.java @@ -523,15 +523,21 @@ public class Node implements Closeable { boolean clean = true; for (final String defaultPathData : Environment.DEFAULT_PATH_DATA_SETTING.get(settings)) { - final Path nodeDirectory = NodeEnvironment.resolveNodePath(getPath(defaultPathData), nodeEnv.getNodeLockId()); - if (Files.exists(nodeDirectory) == false) { + final Path defaultNodeDirectory = NodeEnvironment.resolveNodePath(getPath(defaultPathData), nodeEnv.getNodeLockId()); + if (Files.exists(defaultNodeDirectory) == false) { continue; } - final NodeEnvironment.NodePath nodePath = new NodeEnvironment.NodePath(nodeDirectory); + + if (isDefaultPathDataInPathData(nodeEnv, defaultNodeDirectory)) { + continue; + } + + final NodeEnvironment.NodePath nodePath = new NodeEnvironment.NodePath(defaultNodeDirectory); final Set availableIndexFolders = nodeEnv.availableIndexFoldersForPath(nodePath); if (availableIndexFolders.isEmpty()) { continue; } + clean = false; logger.error("detected index data in default.path.data [{}] where there should not be any", nodePath.indicesPath); for (final String availableIndexFolder : availableIndexFolders) { @@ -554,6 +560,15 @@ public class Node implements Closeable { throw new IllegalStateException(message); } + private static boolean isDefaultPathDataInPathData(final NodeEnvironment nodeEnv, final Path defaultNodeDirectory) throws IOException { + for (final NodeEnvironment.NodePath dataPath : nodeEnv.nodePaths()) { + if (Files.isSameFile(dataPath.path, defaultNodeDirectory)) { + return true; + } + } + return false; + } + @SuppressForbidden(reason = "read path that is not configured in environment") private static Path getPath(final String path) { return PathUtils.get(path); diff --git a/test/framework/src/main/java/org/elasticsearch/node/NodeTests.java b/core/src/test/java/org/elasticsearch/node/NodeTests.java similarity index 100% rename from test/framework/src/main/java/org/elasticsearch/node/NodeTests.java rename to core/src/test/java/org/elasticsearch/node/NodeTests.java diff --git a/qa/evil-tests/src/test/java/org/elasticsearch/node/EvilNodeTests.java b/qa/evil-tests/src/test/java/org/elasticsearch/node/EvilNodeTests.java new file mode 100644 index 00000000000..ac29902627d --- /dev/null +++ b/qa/evil-tests/src/test/java/org/elasticsearch/node/EvilNodeTests.java @@ -0,0 +1,77 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.node; + +import org.apache.logging.log4j.Logger; +import org.elasticsearch.common.UUIDs; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.env.Environment; +import org.elasticsearch.env.NodeEnvironment; +import org.elasticsearch.test.ESTestCase; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +public class EvilNodeTests extends ESTestCase { + + public void testDefaultPathDataIncludedInPathData() throws IOException { + final Path zero = createTempDir().toAbsolutePath(); + final Path one = createTempDir().toAbsolutePath(); + final int random = randomIntBetween(0, 2); + final Path defaultPathData; + final Path choice = randomFrom(zero, one); + switch (random) { + case 0: + defaultPathData = choice; + break; + case 1: + defaultPathData = createTempDir().toAbsolutePath().resolve("link"); + Files.createSymbolicLink(defaultPathData, choice); + break; + case 2: + defaultPathData = createTempDir().toAbsolutePath().resolve("link"); + Files.createLink(defaultPathData, choice); + break; + default: + throw new AssertionError(Integer.toString(random)); + } + final Settings settings = Settings.builder() + .put("path.home", createTempDir().toAbsolutePath()) + .put("path.data.0", zero) + .put("path.data.1", one) + .put("default.path.data", defaultPathData) + .build(); + try (NodeEnvironment nodeEnv = new NodeEnvironment(settings, new Environment(settings))) { + final Path defaultPathDataWithNodesAndId = defaultPathData.resolve("nodes/0"); + Files.createDirectories(defaultPathDataWithNodesAndId); + final NodeEnvironment.NodePath defaultNodePath = new NodeEnvironment.NodePath(defaultPathDataWithNodesAndId); + Files.createDirectories(defaultNodePath.indicesPath.resolve(UUIDs.randomBase64UUID())); + final Logger mock = mock(Logger.class); + // nothing should happen here + Node.checkForIndexDataInDefaultPathData(settings, nodeEnv, mock); + verifyNoMoreInteractions(mock); + } + } + +}