diff --git a/.circleci/config.yml b/.circleci/config.yml index 4e7cfd25..5e2695eb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -138,6 +138,15 @@ jobs: - run: name: Execute integration tests command: /usr/bin/entrypoint test + "tests/driver-loader/integration": + machine: + image: ubuntu-1604:202004-01 + steps: + - attach_workspace: + at: /tmp/ws + - run: + name: Execute driver-loader integration tests + command: /tmp/ws/source/falco/test/driver-loader/run_test.sh /tmp/ws/build/release/ # Sign rpm packages "rpm/sign": docker: @@ -306,6 +315,9 @@ workflows: - "tests/integration": requires: - "build/centos7" + - "tests/driver-loader/integration": + requires: + - "build/centos7" - "rpm/sign": context: falco filters: @@ -333,6 +345,7 @@ workflows: only: master requires: - "publish/packages-dev" + - "tests/driver-loader/integration" release: jobs: - "build/centos7": diff --git a/test/driver-loader/run_test.sh b/test/driver-loader/run_test.sh new file mode 100755 index 00000000..0067d811 --- /dev/null +++ b/test/driver-loader/run_test.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# +# Copyright (C) 2020 The Falco Authors. +# +# +# 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. +# +set -euo pipefail + +BUILD_DIR=$1 + +SCRIPT=$(readlink -f $0) +SCRIPTDIR=$(dirname $SCRIPT) +RUNNERDIR="${SCRIPTDIR}/runner" +FALCO_VERSION=$(cat ${BUILD_DIR}/userspace/falco/config_falco.h | grep 'FALCO_VERSION ' | cut -d' ' -f3 | sed -e 's/^"//' -e 's/"$//') +DRIVER_VERSION=$(cat ${BUILD_DIR}/userspace/falco/config_falco.h | grep 'DRIVER_VERSION ' | cut -d' ' -f3 | sed -e 's/^"//' -e 's/"$//') +FALCO_PACKAGE="falco-${FALCO_VERSION}-x86_64.tar.gz" + +cp "${BUILD_DIR}/${FALCO_PACKAGE}" "${RUNNERDIR}" +pushd ${RUNNERDIR} +docker build --build-arg FALCO_VERSION="$FALCO_VERSION" \ + -t falcosecurity/falco:test-driver-loader \ + -f "${RUNNERDIR}/Dockerfile" ${RUNNERDIR} +popd +rm -f "${RUNNERDIR}/${FALCO_PACKAGE}" + +docker run --rm --privileged \ + -e FALCO_VERSION="$FALCO_VERSION" \ + -e DRIVER_VERSION="$DRIVER_VERSION" \ + -v /dev:/host/dev \ + -v /proc:/host/proc:ro \ + -v /boot:/host/boot:ro \ + -v /lib/modules:/host/lib/modules:ro \ + -v /usr:/host/usr:ro \ + -v /etc:/host/etc:ro \ + falcosecurity/falco:test-driver-loader + +docker rmi -f falcosecurity/falco:test-driver-loader \ No newline at end of file diff --git a/test/driver-loader/runner/Dockerfile b/test/driver-loader/runner/Dockerfile new file mode 100644 index 00000000..5a0fbd1d --- /dev/null +++ b/test/driver-loader/runner/Dockerfile @@ -0,0 +1,33 @@ +FROM ubuntu:18.04 + +ARG FALCO_VERSION= +RUN test -n FALCO_VERSION +ENV FALCO_VERSION ${FALCO_VERSION} +ENV DRIVER_VERSION= +ENV HOST_ROOT=/host + +# Minimal set of deps required to run falco-driver-loader and falco +RUN apt-get update -y +RUN apt-get install -y --no-install-recommends \ + ca-certificates \ + libyaml-0-2 \ + dkms \ + curl \ + gcc \ + clang-7 \ + llvm-7 \ + libelf-dev + +RUN rm -rf /usr/bin/clang \ + && rm -rf /usr/bin/llc \ + && ln -s /usr/bin/clang-7 /usr/bin/clang \ + && ln -s /usr/bin/llc-7 /usr/bin/llc + +RUN rm -rf /lib/modules \ + && ln -s $HOST_ROOT/lib/modules /lib/modules + +ADD falco-${FALCO_VERSION}-x86_64.tar.gz / +RUN cp -R /falco-${FALCO_VERSION}-x86_64/* / + +COPY test.sh / +CMD /test.sh \ No newline at end of file diff --git a/test/driver-loader/runner/test.sh b/test/driver-loader/runner/test.sh new file mode 100755 index 00000000..dd66212b --- /dev/null +++ b/test/driver-loader/runner/test.sh @@ -0,0 +1,152 @@ +#!/usr/bin/env bash +# +# Copyright (C) 2020 The Falco Authors. +# +# +# 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. +# +set -euo pipefail + +FALCO="falco -M 1" +FALCO_DRIVER_LOADER=falco-driver-loader +DRIVER_NAME=falco +KERNEL_RELEASE=$(uname -r) +KERNEL_VERSION=$(uname -v | sed 's/#\([[:digit:]]\+\).*/\1/') + + +function get_target_id() { + if [ -f "${HOST_ROOT}/etc/os-release" ]; then + # freedesktop.org and systemd + # shellcheck source=/dev/null + source "${HOST_ROOT}/etc/os-release" + OS_ID=$ID + elif [ -f "${HOST_ROOT}/etc/debian_version" ]; then + # Older Debian + # fixme > can this happen on older Ubuntu? + OS_ID=debian + elif [ -f "${HOST_ROOT}/etc/centos-release" ]; then + # Older CentOS + OS_ID=centos + else + >&2 echo "Detected an unsupported target system, please get in touch with the Falco community" + exit 1 + fi + + case "${OS_ID}" in + ("amzn") + if [[ $VERSION_ID == "2" ]]; then + TARGET_ID="amazonlinux2" + else + TARGET_ID="amazonlinux" + fi + ;; + ("ubuntu") + if [[ $KERNEL_RELEASE == *"aws"* ]]; then + TARGET_ID="ubuntu-aws" + else + TARGET_ID="ubuntu" + fi + ;; + (*) + TARGET_ID=$(echo "${OS_ID}" | tr '[:upper:]' '[:lower:]') + ;; + esac +} + +function cleanup_drivers() { + echo "CLEANUP: remove drivers, if any" + + # kernel module + rmmod "$DRIVER_NAME" > /dev/null 2>&1 || true + dkms uninstall "$DRIVER_NAME/$DRIVER_VERSION" > /dev/null 2>&1 || true + rm -f "$FALCO_KERNEL_MODULE_PATH" + + # bpf probe + rm -f "$FALCO_BPF_PROBE_PATH" + rm -f "$PROBE_INSTALL_PATH" +} + +function run_test() { + echo "" + echo "TEST: $1" + cleanup_drivers + echo "" + $1 + echo "" + echo "PASS: $1" + echo "" +} + +function assert_kernel_module() { + echo "ASSERT: module loaded" + local KMOD_NAME=$(echo "${DRIVER_NAME}" | tr "-" "_") + if ! lsmod | grep "${KMOD_NAME}" > /dev/null 2>&1; then + echo "FAIL: module not loaded" + exit 1 + fi + echo "ASSERT: falco works with module" + if ! $FALCO; then + echo "FAIL: falco does not work with module" + exit 1 + fi +} + +function assert_bpf_probe() { + echo "ASSERT: eBPF probe at $PROBE_INSTALL_PATH" + if ! test -f "$PROBE_INSTALL_PATH"; then + echo "FAIL: eBPF probe not found" + exit 1 + fi + echo "ASSERT: falco works with bpf" + if ! FALCO_BPF_PROBE="" $FALCO; then + echo "FAIL: falco does not work with bpf" + exit 1 + fi +} + +function test_kernel_module() { + $FALCO_DRIVER_LOADER + assert_kernel_module +} + + +function test_bpf_probe() { + $FALCO_DRIVER_LOADER bpf + assert_bpf_probe +} + +echo "falco-driver-loader tester" +echo "" +echo "Falco version: $FALCO_VERSION" +echo "Driver version: $DRIVER_VERSION" +echo "HOST_ROOT: ${HOST_ROOT}" +echo "" + +if [ -n "${HOST_ROOT}" ]; then + echo "Setting up /usr/src links from host" + for i in "$HOST_ROOT/usr/src"/* + do + base=$(basename "$i") + ln -s "$i" "/usr/src/$base" + done +fi + +get_target_id +FALCO_KERNEL_MODULE_PATH="${HOME}/.falco/${DRIVER_NAME}_${TARGET_ID}_${KERNEL_RELEASE}_${KERNEL_VERSION}.ko" +FALCO_BPF_PROBE_PATH="${HOME}/.falco/${DRIVER_NAME}_${TARGET_ID}_${KERNEL_RELEASE}_${KERNEL_VERSION}.o" +PROBE_INSTALL_PATH="${HOME}/.falco/${DRIVER_NAME}-bpf.o" + +run_test "test_kernel_module" +run_test "test_bpf_probe" + +cleanup_drivers \ No newline at end of file