aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Philipp Wollermann <philwo@google.com>2015-10-06 11:49:28 +0000
committerGravatar Laszlo Csomor <laszlocsomor@google.com>2015-10-06 12:26:57 +0000
commit4b40a5fccd3c9c63eea44b3eb173760dc88be743 (patch)
tree0ac0428c9e1804a66893d4f534c254f3f0747a20 /src
parentb504305394b284e872eefdaaec8ba56bb607cebb (diff)
sandbox: Improve MountMap to always return entries sorted by path depth and lexicographical order. This prevents certain edge cases in the sandbox, where a mounted child directory could be hidden by a later mount of a parent directory over its parent.
-- MOS_MIGRATED_REVID=104749937
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java43
-rw-r--r--src/main/java/com/google/devtools/build/lib/sandbox/MountMap.java22
-rw-r--r--src/test/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategyTest.java64
-rw-r--r--src/test/java/com/google/devtools/build/lib/sandbox/MountMapTest.java110
4 files changed, 143 insertions, 96 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java
index 945f267f03..a7657ad6af 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java
@@ -193,7 +193,7 @@ public class LinuxSandboxedStrategy implements SpawnActionContext {
private ImmutableMap<Path, Path> getMounts(
Spawn spawn, ActionExecutionContext executionContext) throws IOException {
- MountMap<Path, Path> mounts = new MountMap<>();
+ MountMap mounts = new MountMap();
mounts.putAll(mountUsualUnixDirs());
mounts.putAll(withRecursedDirs(setupBlazeUtils()));
mounts.putAll(withRecursedDirs(mountRunfilesFromManifests(spawn)));
@@ -230,9 +230,8 @@ public class LinuxSandboxedStrategy implements SpawnActionContext {
* @return a new mounts multimap with the added mounts.
*/
@VisibleForTesting
- static MountMap<Path, Path> withResolvedSymlinks(Map<Path, Path> mounts)
- throws IOException {
- MountMap<Path, Path> fixedMounts = new MountMap<>();
+ static MountMap withResolvedSymlinks(Map<Path, Path> mounts) throws IOException {
+ MountMap fixedMounts = new MountMap();
for (Entry<Path, Path> mount : mounts.entrySet()) {
Path target = mount.getKey();
Path source = mount.getValue();
@@ -253,8 +252,8 @@ public class LinuxSandboxedStrategy implements SpawnActionContext {
* @return a new mounts multimap with the added mounts.
*/
@VisibleForTesting
- static MountMap<Path, Path> withRecursedDirs(Map<Path, Path> mounts) throws IOException {
- MountMap<Path, Path> fixedMounts = new MountMap<>();
+ static MountMap withRecursedDirs(Map<Path, Path> mounts) throws IOException {
+ MountMap fixedMounts = new MountMap();
for (Entry<Path, Path> mount : mounts.entrySet()) {
Path target = mount.getKey();
Path source = mount.getValue();
@@ -275,8 +274,8 @@ public class LinuxSandboxedStrategy implements SpawnActionContext {
* Mount a certain set of unix directories to make the usual tools and libraries available to the
* spawn that runs.
*/
- private MountMap<Path, Path> mountUsualUnixDirs() throws IOException {
- MountMap<Path, Path> mounts = new MountMap<>();
+ private MountMap mountUsualUnixDirs() throws IOException {
+ MountMap mounts = new MountMap();
FileSystem fs = blazeDirs.getFileSystem();
mounts.put(fs.getPath("/bin"), fs.getPath("/bin"));
mounts.put(fs.getPath("/etc"), fs.getPath("/etc"));
@@ -298,8 +297,8 @@ public class LinuxSandboxedStrategy implements SpawnActionContext {
/**
* Mount the embedded tools.
*/
- private MountMap<Path, Path> setupBlazeUtils() throws IOException {
- MountMap<Path, Path> mounts = new MountMap<>();
+ private MountMap setupBlazeUtils() throws IOException {
+ MountMap mounts = new MountMap();
Path mount = blazeDirs.getEmbeddedBinariesRoot().getRelative("build-runfiles");
mounts.put(mount, mount);
return mounts;
@@ -308,9 +307,8 @@ public class LinuxSandboxedStrategy implements SpawnActionContext {
/**
* Mount all runfiles that the spawn needs as specified in its runfiles manifests.
*/
- private MountMap<Path, Path> mountRunfilesFromManifests(Spawn spawn)
- throws IOException {
- MountMap<Path, Path> mounts = new MountMap<>();
+ private MountMap mountRunfilesFromManifests(Spawn spawn) throws IOException {
+ MountMap mounts = new MountMap();
for (Entry<PathFragment, Artifact> manifest : spawn.getRunfilesManifests().entrySet()) {
String manifestFilePath = manifest.getValue().getPath().getPathString();
Preconditions.checkState(!manifest.getKey().isAbsolute());
@@ -321,9 +319,8 @@ public class LinuxSandboxedStrategy implements SpawnActionContext {
return mounts;
}
- static MountMap<Path, Path> parseManifestFile(
- Path targetDirectory, File manifestFile) throws IOException {
- MountMap<Path, Path> mounts = new MountMap<>();
+ static MountMap parseManifestFile(Path targetDirectory, File manifestFile) throws IOException {
+ MountMap mounts = new MountMap();
for (String line : Files.readLines(manifestFile, Charset.defaultCharset())) {
String[] fields = line.trim().split(" ");
Path source;
@@ -346,9 +343,8 @@ public class LinuxSandboxedStrategy implements SpawnActionContext {
/**
* Mount all runfiles that the spawn needs as specified via its runfiles suppliers.
*/
- private MountMap<Path, Path> mountRunfilesFromSuppliers(Spawn spawn)
- throws IOException {
- MountMap<Path, Path> mounts = new MountMap<>();
+ private MountMap mountRunfilesFromSuppliers(Spawn spawn) throws IOException {
+ MountMap mounts = new MountMap();
FileSystem fs = blazeDirs.getFileSystem();
Map<PathFragment, Map<PathFragment, Artifact>> rootsAndMappings =
spawn.getRunfilesSupplier().getMappings();
@@ -370,10 +366,9 @@ public class LinuxSandboxedStrategy implements SpawnActionContext {
/**
* Mount all inputs of the spawn.
*/
- private MountMap<Path, Path> mountInputs(
- Spawn spawn, ActionExecutionContext actionExecutionContext)
+ private MountMap mountInputs(Spawn spawn, ActionExecutionContext actionExecutionContext)
throws IOException {
- MountMap<Path, Path> mounts = new MountMap<>();
+ MountMap mounts = new MountMap();
List<ActionInput> inputs =
ActionInputHelper.expandMiddlemen(
@@ -404,8 +399,8 @@ public class LinuxSandboxedStrategy implements SpawnActionContext {
* <p>If --run_under= refers to a label, it is automatically provided in the spawn's input files,
* so mountInputs() will catch that case.
*/
- private MountMap<Path, Path> mountRunUnderCommand(Spawn spawn) {
- MountMap<Path, Path> mounts = new MountMap<>();
+ private MountMap mountRunUnderCommand(Spawn spawn) {
+ MountMap mounts = new MountMap();
if (spawn.getResourceOwner() instanceof TestRunnerAction) {
TestRunnerAction testRunnerAction = ((TestRunnerAction) spawn.getResourceOwner());
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/MountMap.java b/src/main/java/com/google/devtools/build/lib/sandbox/MountMap.java
index 4e0ae07e41..5051d27df3 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/MountMap.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/MountMap.java
@@ -13,26 +13,30 @@
// limitations under the License.
package com.google.devtools.build.lib.sandbox;
-import com.google.common.collect.ForwardingMap;
+import com.google.common.collect.ForwardingSortedMap;
+import com.google.devtools.build.lib.vfs.Path;
-import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
/**
* A map that throws an exception when trying to replace a key (i.e. once a key gets a value,
* any additional attempt of putting a value on the same key will throw an exception).
+ *
+ * <p>Returns entries sorted by path depth (shorter paths first) and in lexicographical order.
*/
-final class MountMap<K, V> extends ForwardingMap<K, V> {
- final LinkedHashMap<K, V> delegate = new LinkedHashMap<>();
+final class MountMap extends ForwardingSortedMap<Path, Path> {
+ final TreeMap<Path, Path> delegate = new TreeMap<>();
@Override
- protected Map<K, V> delegate() {
+ protected SortedMap<Path, Path> delegate() {
return delegate;
}
@Override
- public V put(K key, V value) {
- V previousValue = get(key);
+ public Path put(Path key, Path value) {
+ Path previousValue = get(key);
if (previousValue == null) {
return super.put(key, value);
} else if (previousValue.equals(value)) {
@@ -44,8 +48,8 @@ final class MountMap<K, V> extends ForwardingMap<K, V> {
}
@Override
- public void putAll(Map<? extends K, ? extends V> map) {
- for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
+ public void putAll(Map<? extends Path, ? extends Path> map) {
+ for (Entry<? extends Path, ? extends Path> entry : map.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
diff --git a/src/test/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategyTest.java b/src/test/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategyTest.java
index b5bcace951..74016762f4 100644
--- a/src/test/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategyTest.java
+++ b/src/test/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategyTest.java
@@ -240,9 +240,7 @@ public class LinuxSandboxedStrategyTest extends LinuxSandboxedStrategyTestCase {
Charset.defaultCharset(),
String.format("x/testfile %s\nx/emptyfile \n", testFile.getPathString()));
- MountMap<Path, Path> mounts =
- LinuxSandboxedStrategy.parseManifestFile(
- targetDir, manifestFile.getPathFile());
+ Map mounts = LinuxSandboxedStrategy.parseManifestFile(targetDir, manifestFile.getPathFile());
assertThat(userFriendlyMap(mounts))
.isEqualTo(
@@ -253,64 +251,4 @@ public class LinuxSandboxedStrategyTest extends LinuxSandboxedStrategyTestCase {
fileSystem.getPath("/runfiles/x/emptyfile"),
fileSystem.getPath("/dev/null"))));
}
-
- @Test
- public void testMountMapWithNormalMounts() throws IOException {
- // Allowed: Just two normal mounts (a -> sandbox/a, b -> sandbox/b)
- MountMap<Path, Path> mounts = new MountMap<>();
- mounts.put(fileSystem.getPath("/a"), workspaceDir.getRelative("a"));
- mounts.put(fileSystem.getPath("/b"), workspaceDir.getRelative("b"));
- assertThat(mounts)
- .isEqualTo(
- ImmutableMap.of(
- fileSystem.getPath("/a"), workspaceDir.getRelative("a"),
- fileSystem.getPath("/b"), workspaceDir.getRelative("b")));
- }
-
- @Test
- public void testMountMapWithSameMountTwice() throws IOException {
- // Allowed: Mount same thing twice (a -> sandbox/a, a -> sandbox/a, b -> sandbox/b)
- MountMap<Path, Path> mounts = new MountMap<>();
- mounts.put(fileSystem.getPath("/a"), workspaceDir.getRelative("a"));
- mounts.put(fileSystem.getPath("/a"), workspaceDir.getRelative("a"));
- mounts.put(fileSystem.getPath("/b"), workspaceDir.getRelative("b"));
- assertThat(mounts)
- .isEqualTo(
- ImmutableMap.of(
- fileSystem.getPath("/a"), workspaceDir.getRelative("a"),
- fileSystem.getPath("/b"), workspaceDir.getRelative("b")));
- }
-
- @Test
- public void testMountMapWithOneThingTwoTargets() throws IOException {
- // Allowed: Mount one thing in two targets (x -> sandbox/a, x -> sandbox/b)
- MountMap<Path, Path> mounts = new MountMap<>();
- mounts.put(fileSystem.getPath("/a"), workspaceDir.getRelative("x"));
- mounts.put(fileSystem.getPath("/b"), workspaceDir.getRelative("x"));
- assertThat(mounts)
- .isEqualTo(
- ImmutableMap.of(
- fileSystem.getPath("/a"), workspaceDir.getRelative("x"),
- fileSystem.getPath("/b"), workspaceDir.getRelative("x")));
- }
-
- @Test
- public void testMountMapWithTwoThingsOneTarget() throws IOException {
- // Forbidden: Mount two things onto the same target (x -> sandbox/a, y -> sandbox/a)
- try {
- MountMap<Path, Path> mounts = new MountMap<>();
- mounts.put(fileSystem.getPath("/x"), workspaceDir.getRelative("a"));
- mounts.put(fileSystem.getPath("/x"), workspaceDir.getRelative("b"));
- fail();
- } catch (IllegalArgumentException e) {
- assertThat(e)
- .hasMessage(
- String.format(
- "Cannot mount both '%s' and '%s' onto '%s'",
- workspaceDir.getRelative("a"),
- workspaceDir.getRelative("b"),
- fileSystem.getPath("/x")));
- }
- }
-
}
diff --git a/src/test/java/com/google/devtools/build/lib/sandbox/MountMapTest.java b/src/test/java/com/google/devtools/build/lib/sandbox/MountMapTest.java
new file mode 100644
index 0000000000..060eb6f264
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/sandbox/MountMapTest.java
@@ -0,0 +1,110 @@
+// Copyright 2015 The Bazel Authors. All rights reserved.
+//
+// Licensed 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 com.google.devtools.build.lib.sandbox;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+import com.google.common.collect.ImmutableMap;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.IOException;
+
+/**
+ * Tests for {@code MountMap}.
+ */
+@RunWith(JUnit4.class)
+public class MountMapTest extends LinuxSandboxedStrategyTestCase {
+ @Test
+ public void testMountMapWithNormalMounts() throws IOException {
+ // Allowed: Just two normal mounts (a -> sandbox/a, b -> sandbox/b)
+ MountMap mounts = new MountMap();
+ mounts.put(fileSystem.getPath("/a"), workspaceDir.getRelative("a"));
+ mounts.put(fileSystem.getPath("/b"), workspaceDir.getRelative("b"));
+ assertThat(mounts)
+ .isEqualTo(
+ ImmutableMap.of(
+ fileSystem.getPath("/a"), workspaceDir.getRelative("a"),
+ fileSystem.getPath("/b"), workspaceDir.getRelative("b")));
+ }
+
+ @Test
+ public void testMountMapWithSameMountTwice() throws IOException {
+ // Allowed: Mount same thing twice (a -> sandbox/a, a -> sandbox/a, b -> sandbox/b)
+ MountMap mounts = new MountMap();
+ mounts.put(fileSystem.getPath("/a"), workspaceDir.getRelative("a"));
+ mounts.put(fileSystem.getPath("/a"), workspaceDir.getRelative("a"));
+ mounts.put(fileSystem.getPath("/b"), workspaceDir.getRelative("b"));
+ assertThat(mounts)
+ .isEqualTo(
+ ImmutableMap.of(
+ fileSystem.getPath("/a"), workspaceDir.getRelative("a"),
+ fileSystem.getPath("/b"), workspaceDir.getRelative("b")));
+ }
+
+ @Test
+ public void testMountMapWithOneThingTwoTargets() throws IOException {
+ // Allowed: Mount one thing in two targets (x -> sandbox/a, x -> sandbox/b)
+ MountMap mounts = new MountMap();
+ mounts.put(fileSystem.getPath("/a"), workspaceDir.getRelative("x"));
+ mounts.put(fileSystem.getPath("/b"), workspaceDir.getRelative("x"));
+ assertThat(mounts)
+ .isEqualTo(
+ ImmutableMap.of(
+ fileSystem.getPath("/a"), workspaceDir.getRelative("x"),
+ fileSystem.getPath("/b"), workspaceDir.getRelative("x")));
+ }
+
+ @Test
+ public void testMountMapWithTwoThingsOneTarget() throws IOException {
+ // Forbidden: Mount two things onto the same target (x -> sandbox/a, y -> sandbox/a)
+ try {
+ MountMap mounts = new MountMap();
+ mounts.put(fileSystem.getPath("/x"), workspaceDir.getRelative("a"));
+ mounts.put(fileSystem.getPath("/x"), workspaceDir.getRelative("b"));
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e)
+ .hasMessage(
+ String.format(
+ "Cannot mount both '%s' and '%s' onto '%s'",
+ workspaceDir.getRelative("a"),
+ workspaceDir.getRelative("b"),
+ fileSystem.getPath("/x")));
+ }
+ }
+
+ @Test
+ public void testMountMapGuaranteesOrdering() {
+ MountMap mounts = new MountMap();
+ mounts.put(fileSystem.getPath("/a/c"), workspaceDir.getRelative("x"));
+ mounts.put(fileSystem.getPath("/b"), workspaceDir.getRelative("x"));
+ mounts.put(fileSystem.getPath("/a/b"), workspaceDir.getRelative("x"));
+ mounts.put(fileSystem.getPath("/a"), workspaceDir.getRelative("x"));
+
+ assertThat(mounts.entrySet())
+ .containsExactlyElementsIn(
+ ImmutableMap.builder()
+ .put(fileSystem.getPath("/a"), workspaceDir.getRelative("x"))
+ .put(fileSystem.getPath("/a/b"), workspaceDir.getRelative("x"))
+ .put(fileSystem.getPath("/a/c"), workspaceDir.getRelative("x"))
+ .put(fileSystem.getPath("/b"), workspaceDir.getRelative("x"))
+ .build()
+ .entrySet())
+ .inOrder();
+ }
+}