blob: 14f110a26e35085bbc3d99907df801aab1cd2934 [file]
#!/bin/bash
#
# Copyright 2015 Google Inc. 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.
#
# Test sandboxing spawn strategy
#
# Load test environment
source $(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/test-setup.sh \
|| { echo "test-setup.sh not found!" >&2; exit 1; }
# namespaces which are used by the sandbox were introduced in 3.8, so
# test won't run on earlier kernels
function check_kernel_version {
if [ "${PLATFORM-}" = "darwin" ]; then
echo "Test will skip: sandbox is not yet supported on Darwin."
exit 0
fi
MAJOR=$(uname -r | sed 's/^\([0-9]*\)\.\([0-9]*\)\..*/\1/')
MINOR=$(uname -r | sed 's/^\([0-9]*\)\.\([0-9]*\)\..*/\2/')
if [ $MAJOR -lt 3 ]; then
echo "Test will skip: sandbox requires kernel >= 3.8; got $(uname -r)"
exit 0
fi
if [ $MAJOR -eq 3 ] && [ $MINOR -lt 8 ]; then
echo "Test will skip: sandbox requires kernel >= 3.8; got $(uname -r)"
exit 0
fi
}
# Some CI systems might deactivate sandboxing
function check_sandbox_allowed {
mkdir -p test
# Create a program that check if unshare(2) is allowed.
cat <<'EOF' > test/test.c
#define _GNU_SOURCE
#include <sched.h>
int main() {
return unshare(CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWUSER);
}
EOF
cat <<'EOF' >test/BUILD
cc_test(name = "sandbox_enabled", srcs = ["test.c"], copts = ["-std=c99"])
EOF
bazel test //test:sandbox_enabled || {
echo "Sandboxing disabled, skipping..."
return false
}
}
function set_up {
mkdir -p examples/genrule
cat << 'EOF' > examples/genrule/a.txt
foo bar bz
EOF
cat << 'EOF' > examples/genrule/b.txt
apples oranges bananas
EOF
# Create cyclic symbolic links to check whether the strategy catches that.
ln -sf cyclic2 examples/genrule/cyclic1
ln -sf cyclic1 examples/genrule/cyclic2
# Create relative symlinks.
mkdir -p examples/genrule/symlinks/{a,ok/sub}
echo OK > examples/genrule/symlinks/ok/x.txt
ln -s $PWD/examples/genrule/symlinks/ok/sub examples/genrule/symlinks/a/b
ln -s ../x.txt examples/genrule/symlinks/a/b/x.txt
cat << 'EOF' > examples/genrule/BUILD
genrule(
name = "works",
srcs = [ "a.txt" ],
outs = [ "works.txt" ],
cmd = "wc $(location :a.txt) > $@",
)
sh_binary(
name = "tool",
srcs = ["tool.sh"],
data = ["datafile"],
)
genrule(
name = "tools_work",
srcs = [],
outs = ["tools.txt"],
cmd = "$(location :tool) $@",
tools = [":tool"],
)
genrule(
name = "tooldir",
srcs = [],
outs = ["tooldir.txt"],
cmd = "ls -l tools/genrule | tee $@ >&2; cat tools/genrule/genrule-setup.sh >&2",
)
genrule(
name = "relative_symlinks",
srcs = [ "symlinks/a/b/x.txt" ],
outs = [ "relative_symlinks.txt" ],
cmd = "cat $(location :symlinks/a/b/x.txt) > $@",
)
genrule(
name = "breaks1",
srcs = [ "a.txt" ],
outs = [ "breaks1.txt" ],
cmd = "wc b.txt a.txt > $@",
)
genrule(
name = "breaks2",
srcs = [ "a.txt" ],
outs = [ "breaks2.txt" ],
# the point of this test is to attempt to read something from filesystem
# that resides outside sandbox by using an absolute path to that file
#
# /home is an arbitrary choice of directory (we doesn't mount it in sandbox
# and it should exist on every linux) which could be changed in case it turns
# out it's necessary to put it in sandbox
#
cmd = "ls /home > $@",
)
genrule(
name = "breaks3",
srcs = [ "cyclic1", "cyclic2" ],
outs = [ "breaks3.txt" ],
cmd = "wc $(location :cyclic1) > $@",
)
EOF
cat << 'EOF' >> examples/genrule/datafile
this is a datafile
EOF
cat << 'EOF' >> examples/genrule/tool.sh
#!/bin/sh
set -e
cp $(dirname $0)/tool.runfiles/examples/genrule/datafile $1
echo "Tools work!"
EOF
chmod +x examples/genrule/tool.sh
}
function test_sandboxed_genrule() {
bazel build --genrule_strategy=sandboxed \
examples/genrule:works \
|| fail "Hermetic genrule failed: examples/genrule:works"
[ -f "${BAZEL_GENFILES_DIR}/examples/genrule/works.txt" ] \
|| fail "Genrule didn't produce output: examples/genrule:works"
}
function test_sandboxed_tooldir() {
bazel build --genrule_strategy=sandboxed \
examples/genrule:tooldir \
|| fail "Hermetic genrule failed: examples/genrule:tooldir"
[ -f "${BAZEL_GENFILES_DIR}/examples/genrule/tooldir.txt" ] \
|| fail "Genrule didn't produce output: examples/genrule:works"
cat "${BAZEL_GENFILES_DIR}/examples/genrule/tooldir.txt" > $TEST_log
expect_log "genrule-setup.sh"
}
function test_sandboxed_genrule_with_tools() {
bazel build --genrule_strategy=sandboxed \
examples/genrule:tools_work \
|| fail "Hermetic genrule failed: examples/genrule:tools_work"
[ -f "${BAZEL_GENFILES_DIR}/examples/genrule/tools.txt" ] \
|| fail "Genrule didn't produce output: examples/genrule:tools_work"
}
# Test for #400: Linux sandboxing and relative symbolic links.
#
# let A = examples/genrule/symlinks/a/b/x.txt -> ../x.txt
# where examples/genrule/symlinks/a/b -> examples/genrule/symlinks/ok/sub
# thus the realpath of A is example/genrule/symlinks/ok/x.txt
# but if the code doesn't correctly resolve intermediate symlinks and instead
# uses string operations to handle ".." parts, it will arrive at:
# examples/genrule/symlinks/a/x.txt, which is wrong.
#
function test_sandbox_relative_symlink_in_inputs() {
bazel build --genrule_strategy=sandboxed \
examples/genrule:relative_symlinks \
|| fail "Hermetic genrule failed: examples/genrule:relative_symlinks"
[ -f "${BAZEL_GENFILES_DIR}/examples/genrule/relative_symlinks.txt" ] \
|| fail "Genrule didn't produce output: examples/genrule:relative_symlinks"
}
function test_sandbox_undeclared_deps() {
bazel build --genrule_strategy=sandboxed \
examples/genrule:breaks1 \
&& fail "Non-hermetic genrule succeeded: examples/genrule:breaks1" || true
[ ! -f "${BAZEL_GENFILES_DIR}/examples/genrule/breaks1.txt" ] || {
output=$(cat "${BAZEL_GENFILES_DIR}/examples/genrule/breaks1.txt")
fail "Non-hermetic genrule breaks1 suceeded with following output: $(output)"
}
}
function test_sandbox_block_filesystem() {
bazel build --genrule_strategy=sandboxed \
examples/genrule:breaks2 \
&& fail "Non-hermetic genrule succeeded: examples/genrule:breaks2" || true
[ ! -f "${BAZEL_GENFILES_DIR}/examples/genrule/breaks2.txt" ] || {
output=$(cat "${BAZEL_GENFILES_DIR}/examples/genrule/breaks2.txt")
fail "Non-hermetic genrule suceeded with following output: $(output)"
}
}
function test_sandbox_cyclic_symlink_in_inputs() {
bazel build --genrule_strategy=sandboxed \
examples/genrule:breaks3 \
&& fail "Genrule with cyclic symlinks succeeded: examples/genrule:breaks3" || true
[ ! -f "${BAZEL_GENFILES_DIR}/examples/genrule/breaks3.txt" ] || {
output=$(cat "${BAZEL_GENFILES_DIR}/examples/genrule/breaks3.txt")
fail "Genrule with cyclic symlinks breaks3 suceeded with following output: $(output)"
}
}
check_kernel_version
check_sandbox_allowed || exit 0
run_suite "sandbox"